home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
m2
/
cat3src
/
cat
/
messages.i
< prev
next >
Wrap
Text File
|
1997-10-26
|
59KB
|
1,870 lines
IMPLEMENTATION MODULE Messages;
FROM SYSTEM IMPORT TSIZE, ADDRESS, ADR, CALLSYS, CADR, BYTE, ASSEMBLER;
(* MM2-Module *)
IMPORT Block, Strings, StrConv, GrafBase, BinOps, MOSGlobals,
Keyboard;
FROM Keyboard IMPORT SpecialCode;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
(* Magic-Module *)
IMPORT MagicAES, MagicVDI, MagicDOS, MagicFSM, mtTextfiles, mtAlerts, mtAppl,
mtUtils, mtDials, mtPopups, MagicXBIOS;
FROM MagicSys IMPORT Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7,
Bit8, Bit9, Bit10, Bit11, Bit12, Bit13, Bit14, Bit15;
(* CAT-Module *)
IMPORT ARCStarter, CatFiles, CatTypes, MTE, MTEdit2,
CatEdit, FontSelect, WdwManager, VDIUtil, ConfVars,
CatGlobal, EditTypes, MausTauschrsc, grinTools, ListHelp,
grin, data, dataSys, QuickSort, Varnames, Infofiles, RectFuncs,
GroupSelect, WinDials, Protokoll;
FROM CatGlobal IMPORT OpenName;
FROM MTPaths IMPORT MessagePath, DataPath, ExportPath, ImportPath, ARCName;
IMPORT ConvertDate;
FROM UserInformation IMPORT UserBLK, batchProcess;
FROM Void IMPORT v;
IMPORT MsgWindow;
CONST emptyStr = 0C;
msgFileName = 'msg'+0C;
msgInfoName = 'msginfo.dat'+0C;
(* Magics fr Header *)
msgCatMagic = 4341544DH; (* "CATM" *)
msgVersion = 2; (* Versionsnummer der MsgManager.i *)
(* msgVersionMagic = 0150H; (* CAT 2.0 bis 2.04 *) *)
msgVersionMagic = 0160H; (* Versionsmagic *)
(*=======================================================================*)
(* Funktionen und Typen fr das Editorfenster *)
(*=======================================================================*)
TYPE
boxHandler = POINTER TO boxHandleRec;
boxHandleRec = RECORD
wdw : INTEGER;
number : INTEGER; (* Messagenummer! *)
r : GrafBase.Rectangle;
infoStr : ARRAY [0..255] OF CHAR;
tree : mtUtils.tObjcTree;
dontUpdate : BOOLEAN;
next : boxHandler;
END;
VAR wdw : INTEGER;
boxList : boxHandler;
(* Messagenummer-Verwaltung: Es wird in dem Set festgehalten, welche Nummern
* schon vergeben wurden und welche nicht. FindNumber gibt die niedrigste freie
* Nummer zurck, ClearNumber lscht die bergebene Nummer aus dem Set
*)
PROCEDURE FindNumber (min : INTEGER) : INTEGER;
VAR i : INTEGER;
BEGIN
min := BinOps.HigherInt (min, 1);
FOR i := min TO 999 DO
IF ~(i IN usedNumbers) THEN INCL (usedNumbers, i); RETURN i; END;
END;
RETURN 1000;
END FindNumber;
PROCEDURE ClearNumber (num : INTEGER);
BEGIN
EXCL (usedNumbers, num);
END ClearNumber;
PROCEDURE FindMessage (number : INTEGER): INTEGER;
VAR i : INTEGER;
BEGIN
FOR i := 0 TO messages - 1 DO
IF msgArray^[i].number = number
THEN RETURN i
END;
END;
RETURN -1;
END FindMessage;
(* Ein paar Hilfsroutinen *)
PROCEDURE Number2Name (number : CARDINAL; VAR str : ARRAY OF CHAR);
(* bergeben wird die Nummer, gibt zurck 'MSGxxx'
* Die Extension mu dann noch angehngt werden.
*)
BEGIN
Strings.Assign (msgFileName, str, v.bool);
Strings.Append (StrConv.NumToStr (number, 10, 3, '0'), str, v.bool);
END Number2Name;
PROCEDURE MakeMyDate (date, time: CARDINAL; VAR myDate: LONGCARD);
(* Erzeugt ein Datum fr IDs,. 24 Bit lang und damit
* 5 Zeichen im 36er System.
* Das Format sieht wie folgt aus:
* Bit 0..5: Minute (6 Bits)
* Bit 6..11: Stunde (5 Bits)
* Bit 12..16: Tag (5 Bits)
* Bit 17..20: Monat (4 Bits)
* Bit 21..24: (Jahr seit 1980) MOD 16 (4 Bits)
*)
VAR j, m, d, s, min : LONGCARD;
BEGIN
d := date MOD 32; (* Tag herausholen *)
date := date DIV 32;
m := date MOD 16; (* Monat herausholen *)
date := date DIV 16;
j := date MOD 16; (* Jahr MOD 16 herausholen *)
time := time DIV 32; (* Sekunden wegrechnen *)
min := time MOD 64;
time := time DIV 64;
s := time MOD 32; (* Sollte eigentlich gar nix mehr wegzurechnen haben *)
(* Nun das neue Datum einpacken *)
myDate := (((((((j * 16) + m) * 32) + d) * 32) + s) * 64) + min;
END MakeMyDate;
PROCEDURE MakeMausId (msg: msgInfo; VAR str : ARRAY OF CHAR);
(* Erzeugt eine ID, wie sie an die Maus geschickt wird.
* Format:
* CM###ddddd, ### ist die interne Messagenummer,
* ddddd ist das Datum und die Zeit im 36er System
*)
VAR myDate : LONGCARD;
BEGIN
Strings.Assign ('CM', str, v.bool);
Strings.Append (StrConv.NumToStr (msg.number, 10, 3, '0'), str, v.bool);
(* Nun wird aus den GEMDOS-Daten ein eigenes Datum erzeugt, da die Maus
* nur IDs mit 10 Stellen annimmt, ich aber mindestens 13 bruchte :-((
* Daher habe ich ein eigenes Format eingebaut, das nicht alle
* Informationen enthlt, aber genau genug ist und 24 Bit belegt.
*)
MakeMyDate (msg.cDate, msg.cTime, myDate);
Strings.Append (StrConv.LNumToStr (myDate, 36, 5, '0'), str, v.bool);
END MakeMausId;
PROCEDURE FileSize (REF path, name : ARRAY OF CHAR; VAR date, time: CARDINAL) : LONGCARD;
VAR fn : CatTypes.String255;
BEGIN
Strings.Assign(path, fn, v.bool);
Strings.Append(name, fn, v.bool);
RETURN CatFiles.FileSizeAndDate (fn, v.bool, date, time);
END FileSize;
PROCEDURE FixDate (idx: INTEGER);
VAR tmpName : CatTypes.String255;
BEGIN
(* Noch altes Format, Dateidatum der Messagedatei nehmen *)
Number2Name (msgArray^[idx].number, tmpName);
Strings.Append (CatTypes.textExt, tmpName, v.bool);
v.lint := FileSize (MessagePath, tmpName,
msgArray^[idx].cDate, msgArray^[idx].cTime);
END FixDate;
PROCEDURE hasNumbers (REF internalId : ARRAY OF CHAR): BOOLEAN;
CONST nums = CatTypes.charSet {'0'..'9'};
BEGIN
RETURN (internalId[2] IN nums) &
(internalId[3] IN nums) &
(internalId[4] IN nums);
END hasNumbers;
PROCEDURE isMessage (REF internalId : ARRAY OF CHAR): BOOLEAN;
VAR msgName : CatTypes.String127;
BEGIN
msgName := msgFileName;
RETURN ((internalId[0] = msgName[0])
& (internalId[1] = msgName[1])
& (internalId[2] = msgName[2]))
OR (hasNumbers (internalId)
& (internalId[0] = 'C')
& (internalId[1] = 'M'));
END isMessage;
PROCEDURE GetMessIdx (REF internalId : ARRAY OF CHAR): INTEGER;
VAR number : INTEGER;
pos : CARDINAL;
numStr : ARRAY [0..7] OF CHAR;
long : BOOLEAN;
idx : INTEGER;
cLong,
xLong : LONGCARD;
msg : msgInfo;
BEGIN
long := FALSE;
IF hasNumbers (internalId)
THEN
pos := 0;
Strings.Copy (internalId, 2, 3, numStr, v.bool);
numStr [3] := '';
number := StrConv.StrToCard (numStr, pos, v.bool);
long := TRUE;
ELSE
pos := 3;
number := StrConv.StrToInt (internalId, pos, v.bool);
END;
idx := FindMessage (number);
IF long & (idx >= 0)
THEN
(* Nun bei langem Format auch noch Datum und Zeit prfen *)
pos := 0;
Strings.Copy (internalId, 5, 5, numStr, v.bool);
xLong := StrConv.StrToLNum (numStr, 36, pos, v.bool);
msg := msgArray^[idx];
MakeMyDate (msg.cDate, msg.cTime, cLong);
IF (xLong = cLong)
THEN
RETURN idx
ELSE
RETURN -1
END;
ELSE
RETURN idx;
END;
END GetMessIdx;
(*=========================================================================*)
PROCEDURE MakeNewMsgArray (force : BOOLEAN; new : CARDINAL) : BOOLEAN;
(* Alloziert ein neues Messagearray und kopiert das alte hinein.
* FALSE: Nicht genug Speicher!
*)
VAR i : INTEGER;
newMax : CARDINAL;
newArray : msgArrayPtr;
BEGIN
IF (messages = maxMess - 1) OR force
THEN
IF force
THEN
newMax := new + 20;
ELSE
newMax := maxMess + 20;
END;
ALLOCATE (newArray, LONG(newMax) * TSIZE (msgInfo));
IF newArray = NIL THEN RETURN FALSE END;
Block.Clear (newArray, LONG(newMax)*TSIZE(msgInfo));
IF msgArray # NIL
THEN
FOR i := 0 TO INTEGER(maxMess) - 1 DO newArray^[i] := msgArray^[i] END;
DEALLOCATE (msgArray, 0);
END;
msgArray := newArray;
FOR i := INTEGER(maxMess) TO INTEGER (newMax) - 1 DO
msgArray^[i].hdrRead := FALSE;
END;
maxMess := newMax;
MsgWindow.MsgSetList (msgArray, FALSE);
(* !!!! msgWindow.list := msgArray; *)
END;
RETURN TRUE;
END MakeNewMsgArray;
(* Array I/O *)
PROCEDURE ReadMessageInfo();
(* Diese Prozedur liest das Infoarray von der
* Platte und zhlt auch am Anfang die Messages
*)
VAR msgHdl : INTEGER;
size : LONGCARD;
mess : CARDINAL;
shortArray : diskArrayPtr;
i : INTEGER;
j : lineType;
dbHdr : dataSys.FileHeaderType;
readMessages : BOOLEAN;
BEGIN
(* Datei ffnen *)
mess := 0;
msgHdl := CatFiles.OpenFile (MessagePath, msgInfoName, CatFiles.readFile);
IF msgHdl = -33 (* File not found *)
THEN
messages := 0;
v.bool := MakeNewMsgArray (TRUE, messages);
readMessages := FALSE;
ELSE
IF msgHdl < 0 THEN CatFiles.ErrorAlert (msgHdl); RETURN END;
CatFiles.Seek (0, msgHdl, CatFiles.end);
size := CatFiles.FilePos (msgHdl);
IF size < dataSys.dbHeaderLength
THEN
messages := 0;
v.bool := MakeNewMsgArray (TRUE, mess);
readMessages := FALSE;
ELSE
mess := SHORT((size - dataSys.dbHeaderLength) DIV TSIZE (shortInfo));
IF mess > 0
THEN
ALLOCATE (shortArray, size - dataSys.dbHeaderLength);
IF shortArray = NIL THEN CatFiles.CloseFile (msgHdl); RETURN END;
IF ~ MakeNewMsgArray (TRUE, mess)
THEN
DEALLOCATE (shortArray, 0);
CatFiles.CloseFile (msgHdl);
RETURN
END;
ELSE
CatFiles.CloseFile (msgHdl);
v.bool := MakeNewMsgArray (TRUE, mess);
END;
readMessages := mess > 0;
END;
END;
IF readMessages
THEN
(* Jetzt erst mal Header einlesen *)
CatFiles.Seek (0, msgHdl, CatFiles.start);
CatFiles.ReadMuch (dataSys.dbHeaderLength, msgHdl, ADR(dbHdr));
IF CatFiles.FileError # CatFiles.NoError
THEN
CatFiles.ErrorAlert (CatFiles.FileError);
CatFiles.CloseFile (msgHdl);
DEALLOCATE (shortArray, 0);
RETURN
END;
(* Jetzt berprfen des Headers *)
IF (dbHdr.CatMagic # msgCatMagic)
OR (dbHdr.Version # msgVersion)
OR (dbHdr.VersionMagic # msgVersionMagic)
THEN
MTE.info (MTE.oldMsgVersion);
CatFiles.CloseFile (msgHdl);
DEALLOCATE (shortArray, 0);
RETURN
END;
(* An den Start der Daten seeken *)
CatFiles.Seek (TSIZE (dataSys.FileHeaderType), msgHdl, CatFiles.start);
(* Alles einlesen in shortArray*)
CatFiles.ReadMuch (size - dataSys.dbHeaderLength, msgHdl, shortArray);
IF CatFiles.FileError # CatFiles.NoError
THEN
CatFiles.ErrorAlert (CatFiles.FileError);
CatFiles.CloseFile (msgHdl);
DEALLOCATE (shortArray, 0);
RETURN
END;
(* und File schlieen *)
CatFiles.CloseFile (msgHdl);
(* alten Speicher freigeben *)
FOR i := 0 TO messages-1 DO
FOR j := dateL TO rNameL DO
IF msgArray^[i].strings[j] # NIL
THEN
DEALLOCATE (msgArray^[i].strings[j], 0);
END;
END;
END;
(* Messageinfo lschen *)
Block.Clear (msgArray, LONG(mess)*TSIZE(msgInfo));
FOR i := 0 TO INTEGER(mess) - 1 DO
msgArray^[i].info := shortArray^[i];
msgArray^[i].hdrRead := FALSE;
msgArray^[i].selected := FALSE;
msgArray^[i].isSend := FALSE;
FOR j := dateL TO rNameL DO
msgArray^[i].strings[j] := NIL;
END;
IF msgArray^[i].cDate = 0
THEN
FixDate (i);
END;
INCL (usedNumbers, msgArray^[i].number);
END;
(* shortarray freigeben *)
DEALLOCATE (shortArray, 0);
messages := mess;
MsgWindow.MsgSetMaxPos (messages-1, TRUE);
END;
END ReadMessageInfo;
PROCEDURE WriteMessageInfo(doRedrawWdw: BOOLEAN);
(* Diese Prozedur schreibt das Info-Array
* fr die Messages weg
*)
VAR shortArray : diskArrayPtr;
i : INTEGER;
msgHdl : INTEGER;
dbHdr : dataSys.FileHeaderType;
BEGIN
IF messages = 0
THEN
v.bool := CatFiles.DeleteFile (MessagePath, msgInfoName);
MsgWindow.MsgCloseIfOpen();
(* !!!!
IF msgWindow.wdw >= 0
THEN
msgClose (msgWindow.wdw);
END;
*)
Protokoll.SendPathUpdate (MessagePath);
RETURN
END;
ALLOCATE (shortArray, LONG(messages) * TSIZE (shortInfo));
IF shortArray = NIL
THEN RETURN END;
FOR i := 0 TO messages-1 DO
shortArray^[i] := msgArray^[i].info;
END;
msgHdl := CatFiles.CreateFile (MessagePath, msgInfoName);
IF msgHdl < 0 THEN
CatFiles.ErrorAlert (msgHdl);
DEALLOCATE (shortArray, 0);
END;
dbHdr.CatMagic := msgCatMagic;
dbHdr.Version := msgVersion;
dbHdr.VersionMagic := msgVersionMagic;
CatFiles.WriteMuch (dataSys.dbHeaderLength, msgHdl, ADR(dbHdr));
IF CatFiles.FileError # CatFiles.NoError
THEN
CatFiles.ErrorAlert (CatFiles.FileError);
DEALLOCATE (shortArray, 0);
CatFiles.CloseFile (msgHdl);
RETURN
END;
CatFiles.WriteMuch (LONG(messages) * TSIZE (shortInfo), msgHdl, shortArray);
IF CatFiles.FileError # CatFiles.NoError
THEN
CatFiles.ErrorAlert (CatFiles.FileError);
END;
DEALLOCATE (shortArray, 0);
CatFiles.CloseFile (msgHdl);
MsgWindow.MsgSetList (msgArray, FALSE);
MsgWindow.MsgSetMaxPos (messages - 1, doRedrawWdw);
END WriteMessageInfo;
PROCEDURE ReReadMessageInfo();
(* Liest die MSGINFO.DAT erneut ein
*)
VAR i : INTEGER;
j : lineType;
BEGIN
(* MSGINFO.DAT neu einlesen *)
(* alten Speicher freigeben *)
FOR i := 0 TO messages-1 DO
FOR j := dateL TO rNameL DO
IF msgArray^[i].strings[j] # NIL
THEN
DEALLOCATE (msgArray^[i].strings[j], 0);
END;
END;
END;
IF msgArray # NIL THEN DEALLOCATE (msgArray, 0); END;
msgArray := NIL;
messages := 0;
usedNumbers := msgNumberSet{};
ReadMessageInfo();
END ReReadMessageInfo;
(* Header-File I/O *)
PROCEDURE deleteMessage (REF internalId : ARRAY OF CHAR; killEdit: BOOLEAN;
changeState : BOOLEAN); FORWARD;
PROCEDURE ReadHdrInfo (VAR msg : msgInfo; externalRef: BOOLEAN);
(* Liest die Header-Zeilen aus der Datei MSGxxx.HDR ein
*)
VAR hdrName : CatTypes.String255;
hdrHdl : mtTextfiles.TEXTFILE;
aLine : CatTypes.String1023;
line : lineType;
idx : INTEGER;
BEGIN
(* Filenamen basteln *)
Number2Name (msg.number, hdrName);
Strings.Append (CatTypes.headerExt, hdrName, v.bool);
Strings.Insert (MessagePath, 0, hdrName, v.bool);
(* File ffnen *)
IF mtTextfiles.OpenTextfile (hdrName, mtTextfiles.READ, 4096, hdrHdl)
THEN
(* Jetzt die einzelnen Zeilen lesen *)
FOR line := dateL TO rNameL DO
aLine := "";
mtTextfiles.ReadLine (hdrHdl, aLine);
mtTextfiles.ReadLn (hdrHdl);
IF msg.strings[line] # NIL
THEN
DEALLOCATE (msg.strings[line], 0);
END;
ALLOCATE (msg.strings[line], LENGTH (aLine)+2);
IF msg.strings[line] = NIL
THEN
(* Out of Memory *)
MTE.noMemAlert();
mtTextfiles.CloseTextfile (hdrHdl);
idx := FindMessage (msg.number);
IF idx >= 0 THEN msgArray^[idx] := msg END;
RETURN
END;
Strings.Assign (aLine, msg.strings[line]^, v.bool);
END;
(* File wieder schlieen *)
mtTextfiles.CloseTextfile (hdrHdl);
msg.hdrRead := TRUE;
IF externalRef
THEN
idx := FindMessage (msg.number);
IF idx >= 0 THEN msgArray^[idx] := msg END;
END;
ELSE
(* prfen, ob die Datei wirklich existiert. Wenn nicht, dann mu
* die Message gelscht werden!
*)
Number2Name (msg.number, hdrName);
Strings.Append (CatTypes.headerExt, hdrName, v.bool);
IF FileSize (MessagePath, hdrName, v.card, v.card) = 0
THEN
(* File nicht da oder leer, weg damit! *)
Number2Name (msg.number, hdrName);
(*
deleteMessage (hdrName, TRUE, TRUE);
*)
ELSE
MTE.noMemAlert();
END;
END;
END ReadHdrInfo;
PROCEDURE WriteHdrInfo (VAR msg : msgInfo);
(* Schreibt die Header-Zeilen in die Datei MSGxxx.HDR
*)
VAR hdrName : CatTypes.String255;
hdrHdl : mtTextfiles.TEXTFILE;
aLine : CatTypes.String1023;
line : lineType;
BEGIN
(* Filenamen basteln *)
Number2Name (msg.number, hdrName);
Strings.Append (CatTypes.headerExt, hdrName, v.bool);
Strings.Insert (MessagePath, 0, hdrName, v.bool);
(* File ffnen *)
IF mtTextfiles.OpenTextfile (hdrName, mtTextfiles.WRITE, 4096, hdrHdl)
THEN
(* Jetzt die einzelnen Zeilen schreiben *)
FOR line := dateL TO rNameL DO
IF msg.strings[line] # NIL THEN
mtTextfiles.WriteLine (hdrHdl, msg.strings[line]^);
END;
mtTextfiles.WriteLn (hdrHdl);
END;
(* File wieder schlieen *)
mtTextfiles.CloseTextfile (hdrHdl);
ELSE
MTE.noMemAlert ();
END;
END WriteHdrInfo;
(*=========================================================================*)
(* Verwaltung der einzelnen Editboxen *)
PROCEDURE CreateHandler (VAR bx : boxHandler) : BOOLEAN;
VAR currBx : boxHandler;
found : BOOLEAN;
BEGIN
found := FALSE;
NEW (bx);
IF bx = NIL THEN RETURN FALSE END;
IF boxList = NIL
THEN
(* noch kein Handler da! *)
boxList := bx;
ELSE
currBx := boxList;
WHILE (currBx # NIL) & ~found DO
IF currBx^.next = NIL
THEN
found := TRUE
ELSE
currBx := currBx^.next;
END;
END;
IF found THEN
currBx^.next := bx;
ELSE
DISPOSE (bx);
bx := NIL;
RETURN FALSE
END;
END;
WITH bx^ DO
dontUpdate := FALSE;
next := NIL;
END;
RETURN TRUE
END CreateHandler;
VAR inCreate : BOOLEAN;
globBx : boxHandler;
PROCEDURE FindHandler ( wdw : INTEGER) : boxHandler;
VAR bx : boxHandler;
BEGIN
bx := boxList;
WHILE bx # NIL DO
IF bx^.wdw = wdw THEN RETURN bx END;
bx := bx^.next;
END;
IF inCreate
THEN
RETURN globBx
END;
RETURN NIL;
END FindHandler;
PROCEDURE MakeInfoStr (msg: msgInfo; VAR str : ARRAY OF CHAR);
BEGIN
WITH msg DO
Strings.Assign ("", str, v.bool);
(*
IF (refId # NIL) & (refId^[0] # '')
THEN
Strings.Append (refId^, str, v.bool);
Strings.Append (' ', str, v.bool);
END;
*)
IF (msgType = mail) OR (msgType = comment) OR (msgType = groupcomment)
THEN
(* Gruppe hinzufgen *)
IF (group # NIL) & (group^[0] # '')
THEN
Strings.Append ('Gr.: ', str, v.bool);
Strings.Append (group^, str, v.bool);
Strings.Append (' ', str, v.bool);
END;
ELSE
IF (receiver # NIL) & (receiver^[0] # '')
THEN
Strings.Append ('An: ', str, v.bool);
Strings.Append (receiver^, str, v.bool);
Strings.Append (' ', str, v.bool);
END;
END;
IF (topic # NIL) & (topic^[0] # '')
THEN
Strings.Append ('Wg.: ', str, v.bool);
Strings.Append (topic^, str, v.bool);
END;
IF LENGTH (str) > 80
THEN
str[80] := 3c;
str[81] := "";
END;
END;
END MakeInfoStr;
PROCEDURE MakeBoxInfo (msg : msgInfo; VAR box: boxHandler): BOOLEAN;
BEGIN
IF CreateHandler(box)
THEN
WITH box^ DO
dontUpdate := FALSE;
number := msg.number;
MakeInfoStr (msg, infoStr);
(* Baum zuweisen *)
tree := MausTauschrsc.TreeAddr^[MausTauschrsc.editctrl];
mtUtils.SetObjcStringAdr (tree, MausTauschrsc.ec_text, ADR(infoStr));
mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, msgDistribs[msg.dist]);
END;
RETURN TRUE
ELSE
RETURN FALSE
END;
END MakeBoxInfo;
PROCEDURE getRect (wdw : INTEGER; wdwRect : GrafBase.Rectangle; VAR userRect, editWork : GrafBase.Rectangle);
VAR bx : boxHandler;
BEGIN
bx := FindHandler (wdw);
IF bx # NIL
THEN
userRect := wdwRect;
userRect.h := bx^.tree^[0].obHeight;
bx^.r := userRect;
WITH editWork DO
x := userRect.x;
y := userRect.y + userRect.h + 1;
w := userRect.w;
h := wdwRect.h - userRect.h - 1;
END;
ELSE
userRect := GrafBase.Rectangle {wdwRect.x, wdwRect.y, 0, 0};
editWork := wdwRect;
END;
END getRect;
PROCEDURE AdaptPos (tree : mtUtils.tObjcTree; r : GrafBase.Rectangle);
BEGIN
WITH tree^[0] DO
obX := r.x;
obY := r.y;
obWidth := r.w;
END;
END AdaptPos;
PROCEDURE SetTree (bx : boxHandler);
VAR idx: INTEGER;
mt : MessageType;
BEGIN
WITH bx^ DO
(* Koordinaten und Inhalt anpassen *)
AdaptPos (tree, r);
mtUtils.SetObjcStringAdr (tree, MausTauschrsc.ec_text, ADR(infoStr));
WITH tree^[MausTauschrsc.ec_text] DO
obWidth := r.w - obX + tree^[0].obX;
END;
idx := FindMessage (number);
IF idx >= 0
THEN
mt := msgArray^[idx].msgType;
mtUtils.SetState (tree, MausTauschrsc.ec_back, MagicAES.DISABLED, ~((mt=comment) OR (mt=answer) OR (mt=groupcomment) OR (mt=persanswer)));
mtUtils.SetState (tree, MausTauschrsc.ec_pop, MagicAES.DISABLED, ~((mt=mail) OR (mt=comment) OR (mt=groupcomment)));
mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, msgDistribs[msgArray^[idx].dist]);
ELSE
mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, "");
END;
END;
END SetTree;
PROCEDURE drawUserBox (wdw, vdiHdl : INTEGER; wdwWork, clip : GrafBase.Rectangle;
textCol, backCol : INTEGER);
VAR bx : boxHandler;
tr : GrafBase.Rectangle;
BEGIN
bx := FindHandler (wdw);
IF bx # NIL
THEN
WITH bx^ DO
SetTree (bx);
VDIUtil.SetTreeColor (tree, textCol, backCol);
mtUtils.ObjcArea (tree, 0, tr);
IF (clip.y + clip.h = tr.y + tr.h) & (- clip.h = mtUtils.ObjcFrame (tree, 0))
THEN
DEC (clip.y); INC (clip.h, 2);
END;
MagicAES.ObjcDraw (tree, 0, 8, clip);
END;
END;
END drawUserBox;
PROCEDURE OpenEditor (VAR msg : msgInfo; new: BOOLEAN; num : INTEGER; offset: INTEGER; forView: BOOLEAN); FORWARD;
(*$H+*)
PROCEDURE openReference (idx: INTEGER);
VAR str: CatTypes.Str1023Ptr;
gr : CARDINAL;
msg: msgInfo;
isPrivate : BOOLEAN;
PROCEDURE getIdNumber(ptr : data.OneGroupHandle):CARDINAL;
BEGIN
RETURN data.NumberOfID(ptr, str^);
END getIdNumber;
BEGIN
msg := msgArray^[idx];
IF ~msg.hdrRead
THEN
ReadHdrInfo (msg, TRUE);
IF ~msg.hdrRead THEN RETURN END;
(* msgArray^[idx] := msg; *)
END;
str := msg.refId;
IF LENGTH(msg.orgGroup^) = 0
THEN
gr := dataSys.private;
isPrivate := TRUE;
ELSE
isPrivate := FALSE;
END;
IF isMessage (msg.refId^) &
(Strings.Pos ('@',msg.refId^, 0) < 0)
THEN
(* Ist ein Kommentar auf eine interne Message! *)
idx := GetMessIdx (msg.refId^);
IF idx >= 0 THEN
OpenEditor (msgArray^[idx], FALSE, -1, 0, FALSE);
END;
ELSIF isPrivate OR GroupSelect.GroupNumber (msg.orgGroup^, gr)
THEN
v.int := grin.grinOpenWithProc(gr, getIdNumber, grin.grinNextMess, 0, grin.mOther);
END;
END openReference;
(*$H=*)
PROCEDURE handleObject (bx : boxHandler; idx : INTEGER; ob : INTEGER; work: GrafBase.Rectangle);
CONST maxOb = 3;
VAR pop: ADDRESS;
BEGIN
pop := MausTauschrsc.TreeAddr^[MausTauschrsc.distribx];
WITH bx^ DO
IF (ob >= 0) & (ob <= maxOb) & ~mtUtils.InState (tree, ob, MagicAES.DISABLED)
& mtUtils.InFlag (tree, ob, MagicAES.SELECTABLE)
THEN
MagicAES.ObjcChange (tree, ob, work, {MagicAES.SELECTED}, 0);
mtUtils.CalcArea (tree, ob, v.r);
WdwManager.RedrawWdw (wdw, GrafBase.Rectangle(v.r));
mtUtils.Bounce();
CASE ob OF
MausTauschrsc.ec_back : openReference (idx); |
MausTauschrsc.ec_edit : IF ~msgArray^[idx].hdrRead
THEN
ReadHdrInfo (msgArray^[idx], FALSE);
END;
IF msgArray^[idx].hdrRead & MsgWindow.changeHdr (msgArray^[idx])
THEN
WriteMessageInfo(FALSE);
MakeInfoStr (msgArray^[idx], infoStr);
WdwManager.RedrawWdw (wdw, r);
MsgWindow.MsgUpdateButtons();
MsgWindow.MsgRedrawEntry(idx);
(* !!!! careForButtons (ADR(msgWindow), TRUE); *)
(* !!!! redrawEntry (idx); *)
END; |
MausTauschrsc.ec_pop : mtUtils.CalcArea (tree, MausTauschrsc.ec_pop, v.r);
v.int := mtPopups.TreePopup (pop, v.r[0], v.r[1], ORD(msgArray^[idx].dist));
IF v.int > 0
THEN
msgArray^[idx].dist := data.tDistribution (v.int-1);
WriteMessageInfo(FALSE);
mtUtils.SetObjcString (tree, MausTauschrsc.ec_dist, msgDistribs[msgArray^[idx].dist]);
WdwManager.RedrawWdw (wdw, r);
MsgWindow.MsgRedrawEntry(idx);
(* !!!! redrawEntry (idx); *)
END; |
ELSE
END;
MagicAES.ObjcChange (tree, ob, work, {}, 0);
mtUtils.CalcArea (tree, ob, v.r);
WdwManager.RedrawWdw (wdw, GrafBase.Rectangle(v.r));
END;
END;
END handleObject;
(* Hier die Handler fr die Box mit den Kommentar-Infos *)
PROCEDURE ClickInInfo (wdw, vdiHdl, mx, my : INTEGER; kState : BITSET; work : GrafBase.Rectangle);
VAR bx : boxHandler;
idx: INTEGER;
ob : INTEGER;
msg: msgInfo;
BEGIN
bx := FindHandler (wdw);
IF bx # NIL
THEN
WITH bx^ DO
idx := FindMessage (number);
IF idx >= 0
THEN
SetTree (bx);
ob := MagicAES.ObjcFind (tree, 0, 8, mx, my);
handleObject (bx, idx, ob, work);
END;
END;
END;
END ClickInInfo;
PROCEDURE handleKey (wdw : INTEGER; VAR scan, c : CHAR; VAR kstate : BITSET; VAR moreChars : BOOLEAN): BOOLEAN;
VAR bx : boxHandler;
idx : INTEGER;
ob : INTEGER;
work : GrafBase.Rectangle;
withAlt : BOOLEAN;
BEGIN
bx := FindHandler (wdw);
IF bx # NIL
THEN
idx := FindMessage (bx^.number);
IF idx >= 0 THEN
moreChars := FALSE;
(* Workarea vom Fenster holen *)
WdwManager.GetWdwWork (wdw, work);
(* Jetzt habe ich den richtigen ASCII-Code *)
withAlt := MagicAES.KALT IN kstate;
IF (CatGlobal.WithAlt (kstate) & (c = 0C)) OR
(CatGlobal.WithCtrl (kstate))
THEN
(* Jetzt Tastencodes richtig holen, das AES erzhlt da nur Mll *)
c := mtUtils.CharCode (INTEGER(ORD(scan)), kstate);
END;
CASE CAP(c) OF
'C': IF withAlt THEN
handleObject (bx, idx, MausTauschrsc.ec_edit, work);
RETURN TRUE
END; |
'D': IF withAlt THEN
handleObject (bx, idx, MausTauschrsc.ec_pop, work);
RETURN TRUE;
END; |
'-': IF MagicAES.KCTRL IN kstate
THEN
handleObject (bx, idx, MausTauschrsc.ec_back, work);
RETURN TRUE
END; |
'Z': IF withAlt & CatGlobal.WithShift (kstate) THEN
(* Zurckstellung umndern *)
IF ~msgArray^[idx].hdrRead
THEN
ReadHdrInfo (msgArray^[idx], FALSE);
END;
IF msgArray^[idx].hdrRead
THEN
msgArray^[idx].sendMsg := ~msgArray^[idx].sendMsg;
WriteMessageInfo(FALSE);
MakeInfoStr (msgArray^[idx], bx^.infoStr);
WdwManager.RedrawWdw (wdw, bx^.r);
MsgWindow.MsgUpdateButtons();
MsgWindow.MsgRedrawEntry(idx);
END;
RETURN TRUE;
END;
ELSE
END
END;
END;
RETURN MTEdit2.ChangeThisChar (wdw, scan, c, kstate, moreChars);
END handleKey;
PROCEDURE userClose (wdw : INTEGER);
VAR bx, boxi : boxHandler;
idx : INTEGER;
msgName : CatTypes.String255;
size : LONGCARD;
cDt, cTi : CARDINAL;
BEGIN
(* boxHandler wieder aus Liste entfernen und freigeben *)
bx := FindHandler (wdw);
IF bx # NIL
THEN
(* Erstmal nachsehen, ob Text gendert bei neuem Text! *)
idx := FindMessage (bx^.number);
IF (idx >= 0) & ~bx^.dontUpdate
THEN
(* Testen, ob Gre verndert! *)
Number2Name (bx^.number, msgName);
Strings.Append (CatTypes.textExt, msgName, v.bool);
size := FileSize (MessagePath, msgName, cDt, cTi);
(* Jetzt Datum bauen *)
(* Achtung: Dieser Aufruf geht davon aus, da der String
* immer vorhanden und passend gro ist. Diese Annahme ist zulssig,
* da jede Nachricht eine E-Zeile verpat bekommt und auch
* die Lnge der E-Zeile feststeht. Auerdem wird beim Einlesen grozgig
* alloziert.
*)
(* Hier gibt es einen Buserror, wenn der Pointer noch nicht
* alloziert ist
*)
IF ~msgArray^[idx].hdrRead
THEN
ReadHdrInfo (msgArray^[idx], FALSE);
END;
IF msgArray^[idx].date # NIL
THEN
ConvertDate.MakeFreeDate (cDt, cTi, msgArray^[idx].date^);
END;
IF size # msgArray^[idx].size
THEN
msgArray^[idx].size := size;
msgArray^[idx].new := FALSE;
WriteMessageInfo(FALSE);
WriteHdrInfo (msgArray^[idx]);
ELSIF msgArray^[idx].new
THEN
(* Nachsehen, ob noch andere Fenster mit der Nachricht
* offen sind. Wenn nicht, dann Nachricht lschen
*)
boxi := boxList;
WHILE (boxi # NIL) & ((boxi^.number # bx^.number) OR (boxi = bx)) DO
boxi := boxi^.next;
END;
IF boxi = NIL
THEN
deleteMessage (msgName, FALSE, TRUE);
END;
ELSE
WriteHdrInfo (msgArray^[idx]);
END;
END;
IF boxList # bx
THEN
(* Auf Listenanfang gehen *)
boxi := boxList;
(* Handler suchen in Liste *)
WHILE (boxi # NIL) & (boxi^.next # bx) DO
boxi := boxi^.next;
END;
boxi^.next := bx^.next;
ELSE
boxList := bx^.next;
END;
DISPOSE (bx);
END;
END userClose;
PROCEDURE OpenEditor (VAR msg : msgInfo; new: BOOLEAN; num : INTEGER; offset: INTEGER; forView: BOOLEAN);
VAR txtName : CatTypes.String255;
bx : boxHandler;
BEGIN
IF (msg.msgType # forward) & (msg.msgType # copyOther) & (msg.msgType # copyOwn)
THEN
(* Erstmal Headerinformationen einlesen *)
IF ~msg.hdrRead
THEN
ReadHdrInfo (msg, TRUE);
IF ~msg.hdrRead THEN RETURN END;
END;
(* Jetzt Editor aufrufen *)
Number2Name (msg.number, txtName);
Strings.Append (CatTypes.textExt, txtName, v.bool);
Strings.Assign (txtName, OpenName, v.bool);
IF MakeBoxInfo (msg, bx)
THEN
inCreate := TRUE;
globBx := bx;
IF CatEdit.OpenEditor (MessagePath, txtName, FALSE,
TRUE, ADDRESS(ClickInInfo), ADDRESS(getRect), ADDRESS(drawUserBox), ADDRESS (userClose),
ADDRESS (handleKey), NIL, NIL, NIL,
UserBLK.editRight, FALSE, UserBLK.Umbruch, num,
wdw)
THEN
bx^.wdw := wdw;
CatEdit.SetTabsize (wdw, UserBLK.tabSize);
ConfVars.GetConfDefBool (cAutoIndDflt, v.bool, TRUE);
CatEdit.SetMode (wdw, CatEdit.indentMode, v.bool);
IF new THEN CatEdit.EditSetOffset (wdw, offset); END;
IF forView
THEN
CatEdit.SetMode (wdw, CatEdit.roMode, TRUE);
CatEdit.SetMode (wdw, CatEdit.effMode, TRUE);
END;
ELSE
bx^.wdw := -1;
inCreate := FALSE;
userClose (-1); (* direkt wieder lschen! *)
END;
inCreate := FALSE;
ELSE
MTE.noMemAlert ();
END;
END;
END OpenEditor;
(*=========================================================================*)
PROCEDURE CreateMessage (minNum : INTEGER; REF To, OrgGroup, Group, RefId, Topic, RealName : ARRAY OF CHAR;
type : MessageType; copyTo : CARDINAL;
REF crossLine : ARRAY OF CHAR;
REF oldMId : ARRAY OF CHAR;
oldDist : data.tDistribution;
openEditor : BOOLEAN;
VAR messIdx: INTEGER): BOOLEAN;
TYPE lineSet = SET OF lineType;
VAR msg : msgInfo;
txtName : CatTypes.String255;
txtHdl : mtTextfiles.TEXTFILE;
line : lineType;
offset,
idx : INTEGER;
tmpName,
mataGroup: CatTypes.String255;
linesAvail: lineSet;
PROCEDURE freeMsg (complain: BOOLEAN);
VAR i : lineType;
BEGIN
FOR i := dateL TO rNameL DO
IF msg.strings[i] # NIL
THEN
DEALLOCATE (msg.strings[i], 0)
END;
END;
MTE.noMemWarn (complain);
DEC (messages);
END freeMsg;
PROCEDURE CopyLine (VAR x : CatTypes.Str1023Ptr; REF str : ARRAY OF CHAR): BOOLEAN;
BEGIN
ALLOCATE (x, LENGTH (str)+2);
IF x = NIL THEN RETURN FALSE END;
Strings.Assign (str, x^, v.bool);
RETURN LENGTH (str) > 0;
END CopyLine;
BEGIN
IF ~MakeNewMsgArray (FALSE, 0)
THEN RETURN FALSE END;
INC (messages);
msg := msgArray^[messages-1];
messIdx := messages-1;
FOR line := dateL TO rNameL DO
msg.strings[line] := NIL;
END;
ALLOCATE (msg.date, 20);
IF msg.date = NIL THEN DEC (messages); RETURN FALSE END;
(* E-Zeile festlegen *)
ConvertDate.MakeDate (msg.date^);
(* Jetzt die Zeilen kopieren und merken, was ich habe *)
linesAvail := lineSet{dateL};
IF CopyLine (msg.refId, RefId) THEN INCL (linesAvail, refIdL); END;
IF CopyLine (msg.receiver, To) THEN INCL (linesAvail, receiverL); END;
IF CopyLine (msg.topic, Topic) THEN INCL (linesAvail, topicL); END;
IF CopyLine (msg.orgGroup, OrgGroup) THEN INCL (linesAvail, orgGroupL); END;
IF CopyLine (msg.group, Group) THEN INCL (linesAvail, groupL); END;
IF CopyLine (msg.rId, oldMId) THEN INCL (linesAvail, rIdL); END;
IF CopyLine (msg.realName, RealName) THEN INCL (linesAvail, rNameL); END;
(* Jetzt die anderen Infos erzeugen *)
CASE type OF
persanswer,
answer,
groupcomment,
copyOther,
forward,
comment : IF NOT (refIdL IN linesAvail)
THEN
freeMsg(TRUE);
RETURN FALSE
END;
IF ((type # copyOther) & (type # forward) & ~(topicL IN linesAvail))
THEN
freeMsg(TRUE);
RETURN FALSE
END;
IF (type = comment) OR (type = groupcomment) OR (type = persanswer)
THEN
IF (~(groupL IN linesAvail) & (type # persanswer))
OR (~(orgGroupL IN linesAvail) & (type # comment))
THEN
freeMsg(TRUE);
RETURN FALSE
END;
END;
v.bool := receiverL IN linesAvail;
IF ((type = answer) OR (type = persanswer) OR
(type = forward) OR (type = copyOther))
& ~ v.bool THEN
freeMsg(TRUE);
RETURN FALSE
END;|
mail : (* neue ffentliche Nachricht *)
IF NOT ((groupL IN linesAvail) & (topicL IN linesAvail))
THEN
freeMsg(TRUE);
RETURN FALSE
END; |
copyOwn,
private : (* neue private Nachricht *)
(* Kopie einer neuen privaten Nachricht *)
(* Abweichung: Im Stichwort wird der Kommentar fr den Empfnger festgehalten! *)
IF ~(receiverL IN linesAvail)
THEN
freeMsg(TRUE);
RETURN FALSE
END;
IF ((type = private) & ~(topicL IN linesAvail))
THEN
freeMsg(TRUE);
RETURN FALSE
END;
IF type = copyOwn
THEN
msg.refNum := copyTo;
idx := FindMessage (copyTo);
IF (idx >= 0)
THEN
IF msgArray^[idx].copyCount >= 10
THEN
MTE.info (MTE.maxCopyAlert);
freeMsg(FALSE);
RETURN FALSE;
END;
INC (msgArray^[idx].copyCount);
IF msg.refId # NIL THEN DEALLOCATE (msg.refId, 0); END;
IF NOT (CopyLine (msg.refId, RefId))
THEN
freeMsg(TRUE);
RETURN FALSE
END;
END;
END; |
ELSE
END;
(* Jetzt sind alle ntigen Headerzeilen festgesetzt,
* also jetzt die Headerdatei schreiben
*)
msg.number := FindNumber (minNum);
IF msg.number = 1000
THEN
MTE.info (MTE.toMuchMessages);
freeMsg(TRUE);
RETURN FALSE
END;
msg.msgType := type;
msg.sendMsg := TRUE;
msg.dist := data.dNone;
msg.orgDist := oldDist;
msg.copyCount := 0;
msg.toDelete := FALSE;
msg.new := TRUE;
msg.selected := FALSE;
msg.noRefLine := FALSE;
msg.hdrRead := FALSE;
msg.isSend := FALSE;
msg.cDate := MagicDOS.Tgetdate ();
msg.cTime := MagicDOS.Tgettime ();
(* Reserved-Felder Nullen *)
msg.reserved1 := 0;
msg.reserved2 := 0;
msgArray^[messages-1] := msg;
(* Jetzt ist wirklich alles fertig *)
WriteHdrInfo (msg);
IF (type # copyOwn) & (type # copyOther) & (type # forward) & openEditor
THEN
(* Jetzt Textfile erzeugen *)
Number2Name (msg.number, txtName);
Strings.Append (CatTypes.textExt, txtName, v.bool);
Strings.Insert (MessagePath, 0, txtName, v.bool);
IF mtTextfiles.OpenTextfile (txtName, mtTextfiles.WRITE, 120, txtHdl)
THEN
IF crossLine[0] # ''
THEN
mtTextfiles.WriteLine (txtHdl, crossLine);
mtTextfiles.WriteLn(txtHdl);
mtTextfiles.WriteLn(txtHdl);
END;
mtTextfiles.WriteLn(txtHdl);
offset := SHORT(mtTextfiles.Textpos (txtHdl));
ConfVars.GetConfDefStr (cMataGroup, mataGroup, "MT.CAT");
Strings.Upper (mataGroup);
IF (msg.msgType = comment) OR (msg.msgType = groupcomment) OR (msg.msgType = mail)
THEN
Strings.Assign (msg.group^, tmpName, v.bool);
Strings.Upper (tmpName);
IF Strings.StrEqual (tmpName, mataGroup)
THEN
mtTextfiles.WriteLn (txtHdl);
mtTextfiles.WriteLine (txtHdl, '---');
mtTextfiles.WriteLn (txtHdl);
mtTextfiles.WriteLine (txtHdl, 'CAT '+CatTypes.CatVersion+' vom '+CatTypes.CatDate+0C);
mtTextfiles.WriteLn (txtHdl);
END;
END;
msg.size := mtTextfiles.Textpos (txtHdl);
msgArray^[messages-1] := msg;
mtTextfiles.CloseTextfile (txtHdl);
ELSE
MTE.info (MTE.cantCreateFile);
ClearNumber (msg.number);
freeMsg(TRUE);
RETURN FALSE
END;
(* Jetzt existieren HDR und TXT, nur noch MessageInfo wegschreiben *)
WriteMessageInfo(TRUE);
Protokoll.SendPathUpdate (MessagePath);
OpenEditor (msg, TRUE, -1, offset, FALSE);
ELSE
WriteMessageInfo(TRUE);
END;
RETURN TRUE;
END CreateMessage;
PROCEDURE NewMessage(REF Gruppe, Wegen : ARRAY OF CHAR);
(* Eine neue Message anlegen und danach editieren *)
BEGIN
v.bool := CreateMessage (1, '', '', Gruppe, '', Wegen, '', mail, 0, '', '', data.dNone, TRUE, v.int);
END NewMessage;
PROCEDURE NewKomMessage(REF fromGroup, Group, Wegen, RefId, txt, mId, To, RealName: ARRAY OF CHAR);
(* Einen Kommentar zu einer Gruppennachricht in
* eine andere Gruppe schicken.
*)
VAR type : MessageType;
BEGIN
type := groupcomment;
v.bool := CreateMessage (1, To, fromGroup, Group, RefId, Wegen, RealName, type, 0, txt, mId, data.dNone, TRUE, v.int);
END NewKomMessage;
PROCEDURE NewAnsMessage(REF an, realName, fromGroup, Wegen, RefId, txt, mId : ARRAY OF CHAR);
(* Einen Kommentar zu einer Gruppennachricht an jemand
* persnlich schicken.
*)
VAR type : MessageType;
BEGIN
type := persanswer;
v.bool := CreateMessage (1, an, fromGroup, '', RefId, Wegen, realName, type, 0, txt, mId, data.dNone, TRUE, v.int);
END NewAnsMessage;
PROCEDURE NewPersMsg(REF Empfaenger, RealName, Wegen : ARRAY OF CHAR);
(* Eine neue persnliche Nachricht an jemand schicken
*)
BEGIN
v.bool := CreateMessage (1, Empfaenger, '', '', '', Wegen, RealName, private, 0, '', '', data.dNone, TRUE, v.int);
END NewPersMsg;
CONST cRegReceiver = "Dirk Steins @ K2";
cRegRealName = "Dirk Steins";
cRegTopic = "Registrierung CAT 3.0x";
PROCEDURE UpdateFileSize (number: INTEGER);
VAR idx : INTEGER;
msg : msgInfo;
txtName: CatTypes.String127;
BEGIN
idx := FindMessage (number);
IF idx >= 0
THEN
msg := msgArray^[idx];
Number2Name (msg.number, txtName);
Strings.Append (CatTypes.textExt, txtName, v.bool);
msg.size := FileSize (MessagePath, txtName, v.card, v.card);
msg.new := FALSE;
msgArray^[idx] := msg;
WriteMessageInfo(FALSE);
END;
END UpdateFileSize;
PROCEDURE NewRegMsg(VAR number: INTEGER; VAR txtName : ARRAY OF CHAR);
(* Eine neue persnliche Nachricht an jemand schicken
*)
VAR messIdx : INTEGER;
msg : msgInfo;
BEGIN
Strings.Assign ("", txtName, v.bool);
IF CreateMessage (1, cRegReceiver, '', '', '', cRegTopic, cRegRealName, private, 0, '', '', data.dNone, FALSE, messIdx)
THEN
msg := msgArray^[messIdx];
Number2Name (msg.number, txtName);
Strings.Append (CatTypes.textExt, txtName, v.bool);
number := msg.number;
END;
END NewRegMsg;
PROCEDURE NewKom(REF Nr, Wegen, gruppe, mId, To, RealName : ARRAY OF CHAR;
oldDist: data.tDistribution);
(* Einen Kommentar erzeugen
*)
BEGIN
v.bool := CreateMessage (1, To, gruppe, gruppe, Nr, Wegen, RealName, comment, 0, '', mId, oldDist, TRUE, v.int);
END NewKom;
PROCEDURE NewAnswer(REF Nr, Wegen, an, mId, RealName : ARRAY OF CHAR);
(* Eine Antwort erzeugen
*)
BEGIN
v.bool := CreateMessage (1, an, '', '', Nr, Wegen, RealName, answer, 0, '', mId, data.dNone, TRUE, v.int);
END NewAnswer;
PROCEDURE CopyOrForwardMessage (REF Nr, To, RealName, comment : ARRAY OF CHAR; copy : BOOLEAN);
VAR type : MessageType;
BEGIN
IF copy THEN type := copyOther ELSE type := forward; END;
v.bool := CreateMessage (1, To, '', '', Nr, comment, RealName, type, 0, '', '', data.dNone, FALSE, v.int);
END CopyOrForwardMessage;
PROCEDURE CopyOwnMessage (REF mailId, To, RealName, Comment : ARRAY OF CHAR;
minNum : INTEGER);
VAR msgName : CatTypes.String255;
number : INTEGER;
pos : CARDINAL;
BEGIN
(* Nachsehen, ob die ersten drei Zeichen
* gleich msgFileName sind
*)
msgName := msgFileName;
IF (mailId[0] = msgName[0])
& (mailId[1] = msgName[1])
& (mailId[2] = msgName[2])
THEN
(* Ok, ist wirklich eine Message *)
pos := 3;
number := StrConv.StrToInt (mailId, pos, v.bool);
v.bool := CreateMessage (1, To, '', '', mailId, Comment, RealName, copyOwn, number, '', '', data.dNone, FALSE, v.int);
ELSE
(* ?????? *)
END;
END CopyOwnMessage;
PROCEDURE ChangeMessage (REF internalId : ARRAY OF CHAR): BOOLEAN;
(* Wenn die Nachricht ein Kommentar oder eine Antwort ist,
* dann wird daraus eine entsprechende Nachricht mit Wildwestverkettung
* erzeugt, damit die Maus die beim nchsten Mal annimmt.
*)
VAR messIdx : INTEGER;
msgName : CatTypes.String255;
mess : msgInfo;
BEGIN
(* Nachsehen, ob die ersten drei Zeichen
* gleich msgFileName sind
*)
IF isMessage (internalId)
THEN
messIdx := GetMessIdx(internalId);
IF messIdx < 0 THEN RETURN FALSE END;
mess := msgArray^[messIdx];
IF mess.noRefLine
THEN
RETURN FALSE
END;
mess.noRefLine := TRUE;
IF (mess.dist = data.dNone) & (mess.orgDist # data.dNet)
THEN
(* Nur in dem Fall alte Distribution bernehmen *)
mess.dist := mess.orgDist;
END;
msgArray^[messIdx] := mess;
WriteMessageInfo(FALSE);
RETURN TRUE;
END;
RETURN FALSE;
END ChangeMessage;
PROCEDURE deleteMessage (REF internalId : ARRAY OF CHAR; killEdit: BOOLEAN;
changeState : BOOLEAN);
VAR messIdx : INTEGER;
msgName : CatTypes.String255;
i : lineType;
j : INTEGER;
messNum : INTEGER;
parentNum,
parentIdx : INTEGER;
deleteParent : BOOLEAN;
bx : boxHandler;
BEGIN
(* Nachsehen, ob die ersten drei Zeichen
* gleich msgFileName sind
*)
IF isMessage (internalId)
THEN
mtAppl.StoreMouse();
CatGlobal.busyMouse();
(* Ok, ist wirklich eine Message *)
deleteParent := FALSE;
messIdx := GetMessIdx(internalId);
IF messIdx < 0 THEN RETURN END;
WITH msgArray^[messIdx] DO
toDelete := TRUE;
IF copyCount > 0
THEN
WriteMessageInfo(TRUE);
mtAppl.RestoreMouse();
RETURN
END;
FOR i := dateL TO rNameL DO
IF strings[i] # NIL THEN DEALLOCATE (strings[i], 0) END;
END;
IF msgType = copyOwn
THEN
parentIdx := FindMessage (refNum);
IF parentIdx >= 0
THEN
deleteParent := msgArray^[parentIdx].toDelete;
DEC (msgArray^[parentIdx].copyCount);
parentNum := refNum;
END;
END; (* IF *)
IF (msgType = answer) & changeState
THEN
(* Beantwortete Nachricht zurckstellen, falls nicht
* schon eine Antwort vorhanden ist
*)
ReadHdrInfo (msgArray^[messIdx], FALSE);
grin.grinResetState(refId^);
END;
END;
(* Nachricht aus msgArray lschen durch runterkopieren
* der anderen Nachrichten
*)
messNum := msgArray^[messIdx].number;
FOR j := messIdx TO messages-1 DO
msgArray^[j] := msgArray^[j+1];
END;
DEC (messages);
Number2Name (messNum, msgName);
Strings.Append (CatTypes.textExt, msgName, v.bool);
v.bool := CatFiles.DeleteFile (MessagePath, msgName);
CatGlobal.busyMouse();
Number2Name (messNum, msgName);
Strings.Append (CatTypes.headerExt, msgName, v.bool);
v.bool := CatFiles.DeleteFile (MessagePath, msgName);
CatGlobal.busyMouse();
ClearNumber (messNum);
WriteMessageInfo(TRUE);
IF deleteParent THEN
Number2Name (parentNum, msgName);
deleteMessage (msgName, TRUE, changeState);
END;
IF killEdit
THEN
(* Nachsehen, ob zu der Nachricht ein Editor offen ist
* Wenn ja, dann Fenster ohne Rckfrage schlieen!
*)
bx := boxList;
WHILE bx # NIL DO
IF bx^.number = messNum
THEN
(* Force auf TRUE sorgt dafr, das keine Nachfrage kommt *)
v.bool := CatEdit.CloseEditor (bx^.wdw, TRUE);
bx := boxList;
ELSE
bx := bx^.next;
END;
END;
END;
mtAppl.RestoreMouse();
END;
END deleteMessage;
PROCEDURE DeleteMessage (REF internalId : ARRAY OF CHAR);
BEGIN
(* Die hier wird nur von externen Modulen aufgerufen, d.h.
* vom Parser nach dem Einfgen.
* Und dann mu ich den Status nicht zurcksetzen,
* falls es eine Antwort ist.
*)
deleteMessage (internalId, TRUE, FALSE);
END DeleteMessage;
PROCEDURE MsgHasCopys (REF internalId: ARRAY OF CHAR): BOOLEAN;
(* Gibt zurck, ob die Nachricht Kopien hat oder nicht.
* Wenn es keine private Nachricht ist, dann wird immer FALSE
* zurckgegeben
*)
BEGIN
IF isMessage (internalId) & (GetMessIdx (internalId) >= 0)
THEN
RETURN msgArray^[GetMessIdx(internalId)].copyCount > 0;
END;
RETURN FALSE;
END MsgHasCopys;
PROCEDURE IsPrivateMessage (VAR internalId : ARRAY OF CHAR): BOOLEAN;
(* Gibt zurck, ob die Message eine private oder eine
* ffentliche Nachricht ist. Der Parser mu das beim Abarbeiten
* des Logfiles wissen, um evtl. private Nachrichten noch
* einfgen zu knnen.
*)
VAR messIdx : INTEGER;
msgName : CatTypes.String255;
i : INTEGER;
msg : msgInfo;
checkCopys : BOOLEAN;
BEGIN
checkCopys := TRUE;
IF isMessage (internalId) & (GetMessIdx (internalId) >= 0)
THEN
messIdx := GetMessIdx (internalId);
IF ~msgArray^[messIdx].toDelete
THEN
RETURN (msgArray^[messIdx].msgType = answer) OR
(msgArray^[messIdx].msgType = private) OR
(msgArray^[messIdx].msgType = persanswer)
ELSE
checkCopys := TRUE;
END
END;
IF checkCopys
THEN
(* Tscha, jetzt mu ich checken, ob das eine RefId ist *)
FOR i := 0 TO messages - 1 DO
msg := msgArray^[i];
IF (msg.msgType = copyOther) OR (msg.msgType = forward) OR (msg.msgType = copyOwn)
THEN
IF ~msg.hdrRead
THEN
ReadHdrInfo (msg, TRUE);
IF ~msg.hdrRead THEN RETURN FALSE END;
(* msgArray^[i] := msg; *)
END;
IF (msg.refId # NIL) & (Strings.StrEqual(msg.refId^, internalId))
THEN
(* Direkt mal lschen!! *)
(* Spter mal ndern! *)
Number2Name (msg.number, msgName);
Strings.Assign (msgName, internalId, v.bool);
RETURN msg.msgType = copyOwn
END;
END;
END;
END;
RETURN FALSE
END IsPrivateMessage;
PROCEDURE GetHdrInfos (REF internalId : ARRAY OF CHAR; VAR refIdPtr, ToPtr, WegenPtr,
ElinePtr, longRefIdPtr : ADDRESS);
(* Gibt an den Parser die ntigen Informationen zurck,
* um eine persnliche Nachricht einzufgen
*)
VAR messIdx : INTEGER;
msg : msgInfo;
BEGIN
IF isMessage (internalId)
THEN
messIdx := GetMessIdx (internalId);
msg := msgArray^[messIdx];
IF ~msg.hdrRead
THEN
ReadHdrInfo (msg, TRUE);
(* msgArray^[messIdx] := msg; *)
END;
ToPtr := msg.receiver;
ElinePtr := msg.date;
IF msg.msgType = copyOwn
THEN
IF msg.refId # NIL
THEN
messIdx := GetMessIdx (msg.refId^);
msg := msgArray^[messIdx];
IF ~msg.hdrRead
THEN
ReadHdrInfo (msg, TRUE);
(* msgArray^[messIdx] := msg; *)
END;
END;
refIdPtr := msg.refId;
WegenPtr := msg.topic;
longRefIdPtr := msg.rId;
ELSE
refIdPtr := msg.refId;
WegenPtr := msg.topic;
longRefIdPtr := msg.rId;
END;
END;
END GetHdrInfos;
PROCEDURE GetMsgFileName (VAR name : ARRAY OF CHAR);
(* Gibt an den Parser den Dateinamen zurck,
* unter dem die Nachricht gespeichert wurde,
* ohne Extension
*)
VAR messIdx : INTEGER;
BEGIN
IF isMessage (name)
THEN
messIdx := GetMessIdx (name);
Number2Name (msgArray^[messIdx].number, name);
END;
END GetMsgFileName;
PROCEDURE LineOut (file : mtTextfiles.TEXTFILE; ch : ARRAY OF CHAR; REF str : ARRAY OF CHAR);
BEGIN
IF ch[0] # 0C THEN mtTextfiles.WriteLine (file, ch); END;
mtTextfiles.WriteLine (file, str);
mtTextfiles.WriteLn (file);
END LineOut;
PROCEDURE SendState(REF Nr : ARRAY OF CHAR; NewState : CHAR);
VAR stateHdl : mtTextfiles.TEXTFILE; z : CARDINAL;
stateName : CatTypes.String255;
BEGIN
Strings.Assign (MessagePath, stateName, v.bool);
Strings.Append (CatTypes.statusInf, stateName, v.bool);
IF mtTextfiles.OpenTextfile (stateName, mtTextfiles.APPEND, 512, stateHdl)
OR mtTextfiles.OpenTextfile (stateName, mtTextfiles.WRITE, 512, stateHdl)
THEN
LineOut (stateHdl, '#', Nr);
LineOut (stateHdl, 'B', NewState);
mtTextfiles.CloseTextfile (stateHdl);
Protokoll.SendPathUpdate (MessagePath);
ELSE
(* ???? *)
END;
END SendState;
PROCEDURE InitMessages ();
(* MsgArray allozieren und msgFile einlesen *)
BEGIN
IF msgArray # NIL THEN DEALLOCATE (msgArray, 0); END;
messages := 0;
maxMess := 0;
usedNumbers := msgNumberSet{};
ReadMessageInfo();
END InitMessages;
PROCEDURE SortMessages();
(* sortiert das Message-Array*)
VAR sort : POINTER TO ARRAY [0..$FFFF] OF msgInfoPtr;
i : INTEGER;
newArray : msgArrayPtr;
PROCEDURE msgComp (a1, a2 : ADDRESS) : BOOLEAN;
VAR b1, b2 : POINTER TO msgInfoPtr;
p1, p2 : msgInfoPtr;
BEGIN
b1 := a1; b2 := a2;
p1 := msgInfoPtr (b1^);
p2 := msgInfoPtr (b2^);
RETURN p1^.number < p2^.number
END msgComp;
BEGIN
IF messages = 0 THEN RETURN END;
ALLOCATE (sort, LONG(messages) * TSIZE (ADDRESS));
IF sort = NIL THEN RETURN END;
FOR i := 0 TO messages-1 DO
sort^[i] := ADR(msgArray^[i]);
END;
v.bool := QuickSort.sortIt (0, messages-1, sort^, msgComp, TSIZE (ADDRESS), QuickSort.noBreak);
(* Liste wieder zurckbernehmen *)
ALLOCATE (newArray, LONG(maxMess)*TSIZE(msgInfo));
IF newArray = NIL
THEN
DEALLOCATE (sort, 0);
RETURN
END;
FOR i := 0 TO messages-1 DO
newArray^[i] := sort^[i]^;
END;
DEALLOCATE (msgArray, 0);
msgArray := newArray;
DEALLOCATE (sort, 0);
MsgWindow.MsgSetList (msgArray, TRUE);
(* !!!!
IF (msgWindow.wdw >= 0) & ~msgWindow.isHidden
THEN
(* Fenster ist offen *)
msgWindow.list := msgArray;
WdwManager.FullRedrawWdw (msgWindow.wdw);
END;
*)
WriteMessageInfo(TRUE);
END SortMessages;
PROCEDURE UpdateEditors (msg: msgInfo);
VAR bx : boxHandler;
BEGIN
bx := boxList;
WHILE bx # NIL DO
IF bx^.number = msg.number
THEN
MakeInfoStr (msg, bx^.infoStr);
mtUtils.SetObjcString (bx^.tree, MausTauschrsc.ec_dist, msgDistribs[msg.dist]);
WdwManager.RedrawWdw (bx^.wdw, bx^.r);
END;
bx := bx^.next;
END;
END UpdateEditors;
(* Ein paar Auskunftsfunktionen *)
PROCEDURE MsgEditorTop (wdw: INTEGER): BOOLEAN;
(* Liefert zurck, ob gerade ein Message-Editor das Topwindow ist,
* also ein Editor, der diesem Modul bekannt ist
*)
BEGIN
RETURN FindHandler (wdw) # NIL;
END MsgEditorTop;
PROCEDURE MsgEditGetInfos (wdw: INTEGER; info: msgInfoType; VAR str: ARRAY OF CHAR);
(* Gibt die gewnschten Infos zu dem Message-Editor wdw. Wenn die Information
* nicht vorhanden ist, dann wird ein leerer String geliefert
*)
VAR bx : boxHandler;
ptr: CatTypes.Str1023Ptr;
idx: INTEGER;
BEGIN
Strings.Assign ('', str, v.bool);
bx := FindHandler (wdw);
IF bx # NIL
THEN
WITH bx^ DO
idx := FindMessage (number);
IF idx >= 0
THEN
IF ~msgArray^[idx].hdrRead
THEN
ReadHdrInfo (msgArray^[idx], FALSE);
IF ~msgArray^[idx].hdrRead THEN RETURN END;
END;
ptr := msgArray^[idx].strings[lineType(ORD(info)+1)];
IF ptr # NIL THEN Strings.Assign (ptr^, str, v.bool); END;
END;
END;
END;
END MsgEditGetInfos;
PROCEDURE SaveEditPos (VAR max: INTEGER);
(* Sichert die Positionen der Editoren
* Gibt die Anzahl der gesicherten Positionen zurck
*)
VAR bx : boxHandler;
varName : ARRAY [0..127] OF CHAR;
num : INTEGER;
BEGIN
bx := boxList;
max := -1;
WHILE bx # NIL DO
Strings.Concat (cfgEdit, StrConv.IntToStr (bx^.number, 0), varName, v.bool);
num := CatEdit.GetEditNumber(bx^.wdw);
IF bx^.number > max THEN max := bx^.number END;
v.bool := ConfVars.SetConfigInt (varName, num);
CatEdit.EditSaveWdwPos (bx^.wdw);
bx := bx^.next;
END;
END SaveEditPos;
PROCEDURE CloseAllEditors (force: BOOLEAN): BOOLEAN;
(* Schliet alle Nachrichteneditoren
*)
VAR bx : boxHandler;
BEGIN
REPEAT
bx := boxList;
IF bx # NIL
THEN
IF ~CatEdit.CloseEditor (bx^.wdw, force)
THEN RETURN FALSE
END;
END;
UNTIL bx = NIL;
RETURN TRUE;
END CloseAllEditors;
PROCEDURE ReloadEditors ();
VAR bx : boxHandler;
BEGIN
bx := boxList;
WHILE bx # NIL DO
CatEdit.EditReloadText (wdw);
bx := bx^.next;
END;
END ReloadEditors;
PROCEDURE MsgAskForSave();
VAR bx : boxHandler;
BEGIN
bx := boxList;
REPEAT
IF bx # NIL
THEN
CatEdit.AskForSave (bx^.wdw);
bx := bx^.next;
END;
UNTIL bx = NIL;
END MsgAskForSave;
BEGIN
msgArray := NIL;
messages := 0;
maxMess := 0;
END Messages.